package com.warmheart.core.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

public class ClassReflectUtil {

    /**
     * 根据类名反射创建对象
     * 
     * @param name
     *            类名
     * @return 对象
     * @throws Exception
     */
    public static Object getInstance(String name) throws Exception {
        Class<?> cls = Class.forName(name);
        return cls.newInstance();
    }

    /**
     * 反射方法，打印对象的属性，方法，构造器属性
     * 
     * @param obj
     *            被反射对象
     */
    public static void reflect(Object obj) {
        Class<?> cls = obj.getClass();
        System.out.println("************构  造  器************");
        Constructor<?>[] constructors = cls.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("构造器名称:" + constructor.getName() + "\t" + "    " + "构造器参数类型:"
                    + Arrays.toString(constructor.getParameterTypes()));
        }
        System.out.println("************属     性************");
        Field[] fields = cls.getDeclaredFields();
        // cls.getFields() 该方法只能访问共有的属性
        // cls.getDeclaredFields() 可以访问私有属性
        for (Field field : fields) {
            System.out.println("属性名称:" + field.getName() + "\t" + "属性类型:" + field.getType() + "\t");
        }
        System.out.println("************方   法************");
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println("方法名:" + method.getName() + "\t" + "方法返回类型：" + method.getReturnType() + "\t" + "方法参数类型:"
                    + Arrays.toString(method.getParameterTypes()));
        }
    }

    /**
     * 
     * @param obj
     *            访问对象
     * @param filedname
     *            对象的属性
     * @return 返回对象的属性值
     * @throws Exception
     */
    public static Object getFieldValue(Object obj, String filedname) throws Exception {
        // 反射出类型
        Class<?> cls = obj.getClass();
        Field field = null;
        // 反射出类型字段
        for (; cls != Object.class; cls = cls.getSuperclass()) {
            try {
                Field[] fields = cls.getDeclaredFields();
                if (fields != null && fields.length > 0) {
                    for (Field tempField : fields) {
                        if (tempField.getName().equals(filedname)) {
                            field = tempField;
                            break;
                        }
                    }
                }
                if (field != null) {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            }
        }
        if (field == null) {
            throw new Exception(cls.toString() + "中没有名称为" + filedname + "的字段");
        }
        // 获取属性时，压制Java对访问修饰符的检查
        field.setAccessible(true);
        // 在对象obj上读取field属性的值
        Object val = field.get(obj);
        return val;
    }

    /**
     * 
     * @param obj
     *            访问对象
     * @param filedname
     *            对象的属性
     * @return 返回对象的属性值
     * @throws Exception
     */
    public static Object setIdKeyValue(Object obj, String filedname, String value) throws Exception {
        // 反射出类型
        Class<?> cls = obj.getClass();
        Field field = null;
        // 反射出类型字段
        for (; cls != Object.class; cls = cls.getSuperclass()) {
            try {
                Field[] fields = cls.getDeclaredFields();
                if (fields != null && fields.length > 0) {
                    for (Field tempField : fields) {
                        if (tempField.getName().equals(filedname)) {
                            field = tempField;
                            break;
                        }
                    }
                }
                if (field != null) {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            }
        }
        if (field == null) {
            throw new Exception(cls.toString() + "中没有名称为" + filedname + "的字段");
        }
        // 获取属性时，压制Java对访问修饰符的检查
        field.setAccessible(true);
        // ---------------------------------------------------
        // 针对表主键为字符类型进行赋值UUID,如果为int类型采用自增方式
        if (!field.getType().getName().contains("Integer")) {
            field.set(obj, value);
        }
        // ---------------------------------------------------
        // 在对象obj上读取field属性的值
        Object val = field.get(obj);
        field.setAccessible(false);
        return val;
    }

    /**
     * 
     * @param obj
     *            访问对象
     * @param filedname
     *            对象的属性
     * @return 返回对象的属性值
     * @throws Exception
     */
    public static Object setFieldValue(Object obj, String filedname, Object value) throws Exception {
        // 反射出类型
        Class<?> cls = obj.getClass();
        Field field = null;
        // 反射出类型字段
        for (; cls != Object.class; cls = cls.getSuperclass()) {
            try {
                Field[] fields = cls.getDeclaredFields();
                if (fields != null && fields.length > 0) {
                    for (Field tempField : fields) {
                        if (tempField.getName().equals(filedname)) {
                            field = tempField;
                            break;
                        }
                    }
                }
                if (field != null) {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            }
        }
        if (field == null) {
            throw new Exception(cls.toString() + "中没有名称为" + filedname + "的字段");
        }
        // 获取属性时，压制Java对访问修饰符的检查
        field.setAccessible(true);
        field.set(obj, value);

        // 在对象obj上读取field属性的值
        Object val = field.get(obj);
        field.setAccessible(false);
        return val;
    }

    /**
     * 反射调用对象的方法
     * 
     * @param obj
     *            对象
     * @param methodName
     *            方法名称
     * @param paramType
     *            参数类型 new Class[]{int.class,double.class}
     * @param params
     *            参数值 new Object[]{2,3.5}
     * @return
     * @throws Exception
     */
    public static Object readObjMethod(Object obj, String methodName, Class<?>[] paramTypes, Object[] params)
            throws Exception {
        // 发现类型
        Class<?> cls = obj.getClass();
        // 发现方法
        Method method = cls.getDeclaredMethod(methodName, paramTypes);
        // 访问方法时,压制Java对访问修饰符的检查
        method.setAccessible(true);
        Object val = method.invoke(obj, params);
        return val;
    }
}
